<template>
  <div class="editor-box">
    <Toolbar
      class="editor-toolbar"
      :editor="editorRef"
      :defaultConfig="toolbarConfig"
      :mode="mode"
      v-if="!hideToolBar"
    />
    <Editor
      :style="{ height }"
      class="editor-content'"
      v-model="valueHtml"
      :defaultConfig="editorConfig"
      :mode="mode"
      @on-created="handleCreated"
      @on-blur="handleBlur"
    />
  </div>
</template>

<script setup lang="ts" name="WangEditor">
import { onBeforeUnmount, shallowRef, nextTick, computed } from "vue";
import { IToolbarConfig, IEditorConfig } from '@wangeditor/editor'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import '@wangeditor/editor/dist/css/style.css'

// 富文本 DOM 元素
const editorRef = shallowRef()

// 实列化编辑器
const handleCreated = (editor: any) => {
  editorRef.value = editor
  /**
   *  查看所有 Toolbar 
   * nextTick(() => {
   * const editor = editorRef.value
   *   const toolbar = DomEditor.getToolbar(editor)
   *  console.log(toolbar.getConfig())
   * })
   *
   */
}

// 接收父组件参数，并设置默认值
interface RichEditorProps {
  // 富文本值 必传
  value: string
  // 工具栏配置
  toolbarConfig?: Partial<IToolbarConfig>
  // 编辑器配置 非必传（默认为空）
  editorConfig?: Partial<IEditorConfig>
  // 富文本高度 非必传
  height?: string
  // 富文本模式 非必传（默认为 default
  mode?: 'default' | 'simple'
  // 是否隐藏工具栏 非必传（默认为false）
  hideToolBar?: boolean
  // 是否禁用编辑器 非必传（默认为false）
  disabled?: boolean
}
const props = withDefaults(defineProps<RichEditorProps>(), {
  toolbarConfig: () => {
    return {
      // 排除工具栏无用按钮
      // excludeKeys: [
      //   'group-video',
      //   'insertVideo',
      //   'codeBlock',
      //   'emotion',
      //   'todo',
      //   'fontFamily',
      //   'code',
      //   'insertTable',
      //   'blockquote',
      // ],
    }
  },
  editorConfig: () => {
    return {
      placeholder: '请输入内容...',
      MENU_CONF: {},
    }
  },
  height: '300px',
  mode: 'default',
  hideToolBar: false,
  disabled: false,
})

// 判断当前富文本编辑器是否禁用
if (props.disabled) nextTick(() => editorRef.value.disable())

// 富文本的内容监听，触发父组件改变，实现双向数据绑定
type EmitProps = {
  (e: 'update:value', val: string): void
  (e: 'check-validate'): void
}
const emit = defineEmits<EmitProps>()
const valueHtml = computed({
  get() {
    return props.value
  },
  set(val: string) {
    // 防止富文本内容为空时，校验失败
    if (editorRef.value.isEmpty()) val = ''
    emit('update:value', val)
  },
})

/**
 * @description 图片自定义上传
 * @param file 上传的文件
 * @param insertFn 上传成功后的回调函数（插入到富文本编辑器中）
 * */
type InsertFnTypeImg = (url: string, alt?: string, href?: string) => void
props.editorConfig.MENU_CONF!.uploadImage = {
  async customUpload(file: File, insertFn: InsertFnTypeImg) {
    if (!uploadImgValidate(file)) return
    try {
      /**
       *
       * @description 获取 base 64
       * const fr = new FileReader()
       * fr.readAsDataURL(file)
       * fr.onload = () => {
       * console.log('fr.result', fr.result)
       * }
       *
       */

      /**
       * @description 上传服务器
       *
       * const formData = new FormData()
       * formData.append('file', file)
       * const { data } = await uploadImg(formData)
       * insertFn(data.fileUrl)
       */
      const url = URL.createObjectURL(file)
      insertFn(url)
    } catch (error) {
      console.log(error)
    }
  },
}

// 图片上传前判断
const uploadImgValidate = (file: File): boolean => {
  console.log(file)
  return true
}

// 编辑框失去焦点时触发
const handleBlur = () => {
  emit('check-validate')
}

// 组件销毁时，也及时销毁编辑器
onBeforeUnmount(() => {
  if (!editorRef.value) return
  editorRef.value.destroy()
})

defineExpose({
  editor: editorRef,
})
</script>
<style scoped>
.editor-box {
  border: 1px solid #ccc;
}
.editor-toolbar {
    border-bottom: 1px solid #ccc;
  }
</style>
